package com.ruoyi.web.controller.system;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.system.domain.SysApp;
import com.ruoyi.system.domain.SysATrustCode;
import com.ruoyi.system.service.ISysAppService;
import com.ruoyi.system.service.ISysATrustCodeService;
import com.ruoyi.system.service.ISysUserService;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author renzhihao
 * @date 2023/11/29 16:35
 */
@Controller
@RequestMapping("passport/v1")
@Slf4j
@AllArgsConstructor
public class ATrustMockController extends BaseController {

    private final ISysAppService appService;
    private final ISysATrustCodeService aTrustCodeService;
    private final ISysUserService userService;

    @GetMapping("public/auth2ssoLogin")
    public void auth2ssoLogin(@RequestParam String appid, @RequestParam String redirectUrl,
                              @RequestParam String responseType, @RequestParam(required = false) String state,
                              HttpServletResponse response) throws IOException {
        SysApp sysApp = appService.selectAppByClientId(appid);
        if (sysApp == null) {
            response.getWriter().write(JSONUtil.toJsonStr(error("APPID 不存在")));
            response.getWriter().flush();
            return;
        }

        if (!StringUtils.equals(responseType, "code")) {
            response.getWriter().write(JSONUtil.toJsonStr(error("responseType仅支持code")));
            response.getWriter().flush();
            return;
        }

        SysUser sysUser = ShiroUtils.getSysUser();
        if (sysUser == null) {
            String url = "/login?appid=" + appid + "&redirectUrl=" + URLEncoder.encode(redirectUrl, StandardCharsets.UTF_8) + "&responseType=" + responseType;
            if (StringUtils.isNotEmpty(state)) {
                url += "&state=" + state;
            }
            response.sendRedirect(url);
            return;
        }

        log.info("auth2ssoLogin appid:{}\n redirectUrl:{}\n responseType:{}\n state:{}", appid, redirectUrl, responseType, state);
        String code = IdUtil.simpleUUID();
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(redirectUrl);
        builder.queryParam("code", code);
        if (StringUtils.isNotEmpty(state)) {
            builder.queryParam("state", state);
        }

        SysATrustCode sysAtrustCode = new SysATrustCode();
        sysAtrustCode.setCode(code);
        sysAtrustCode.setUserId(sysUser.getUserId());
        sysAtrustCode.setExpireTime(DateUtil.offsetMinute(DateUtil.date(), 5));
        aTrustCodeService.insertCode(sysAtrustCode);
        response.sendRedirect(builder.toUriString());
    }

    @ResponseBody
    @GetMapping("user/getUserInfoByCode")
    public Map<String, Object> getUserInfoByCode(@RequestParam String appid, @RequestParam String code,
                                                 HttpServletRequest request) {
        log.info("getUserInfoByCode appid:{} code:{}", appid, code);
        String xSdpSignature = request.getHeader("X-SDP-Signature");
        log.info("getUserInfoByCode X-SDP-Signature:{}", xSdpSignature);
        SysApp sysApp = appService.selectAppByClientId(appid);
        if (sysApp == null) {
            return Map.of(
                    "code", 75591001,
                    "message", "APPID 不存在"
            );
        }

        Map<String, String> params = new HashMap<>(3);
        params.put("appid", appid);
        params.put("code", code);

        final String paramString = params.entrySet().stream()
                .filter(e -> StringUtils.isNotBlank(e.getValue()))
                .sorted(Map.Entry.comparingByKey(String::compareTo))
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(Collectors.joining("\n"));

        String sign = SecureUtil.hmacSha256(sysApp.getClientSecret().getBytes()).digestHex(paramString);
        if (!StringUtils.equals(xSdpSignature, sign)) {
            return Map.of(
                    "code", 75591006,
                    "message", "签名不正确"
            );
        }

        SysATrustCode sysAtrustCode = aTrustCodeService.selectByCode(code);
        if (sysAtrustCode == null || DateUtil.date().after(sysAtrustCode.getExpireTime())) {
            return Map.of(
                    "code", 75591008,
                    "message", "code 不存在或已过期"
            );
        }

        aTrustCodeService.deleteByCodeAndExpireTime(code);
        SysUser sysUser = userService.selectUserById(sysAtrustCode.getUserId());

        AtrustEntity entity = AtrustEntity.builder()
                .name(sysUser.getLoginName())
                .displayName(sysUser.getUserName())
                .email(sysUser.getEmail())
                .phone(sysUser.getPhonenumber())
                .ip(sysUser.getLoginIp())
                .status(StringUtils.equals(sysUser.getStatus(), "0") ? 1 : 0)
                .externalID(String.valueOf(sysUser.getUserId()))
                .build();

        return Map.of(
                "code", 0,
                "message", "成功",
                "data", entity
        );

    }

    @Data
    @Builder
    public static class AtrustEntity {
        private String name;
        private String email;
        private String phone;
        private String groupPath;
        private String externalID;
        private String description;
        private String ip;
        private String displayName;
        private String password;
        private String expiredTime;
        private Integer status;
        private String userDirectoryName;
        private String userDirectoryType;
        private String band;
        private String clientBrowser;
        private String clientOS;
        private String lastLoginTime;
        private String vip;
        private String authMethod;
    }
}
